<?php 
/*
1 - static functions
2.01 - singleton pattern
*/

define('DBS_SHOW_SELECTS', false);
define('DBS_SHOW_EXPLAIN', false);
define('DBS_GLOBAL_TIMING', false);

//PEAR
require_once 'DB.php';
//pulp
require_once 'Trace.php';

//check conditions
if (!isset($GLOBALS['db']['dsn'])) throw_error('preconditions error', E_USER_ERROR);
if (!isset($GLOBALS['db']['options'])) throw_error('preconditions error', E_USER_ERROR);
//end

class DBs {

	static private $instance;
	private $dbc;
	
	function inst()
	{
		if (!self::$instance)
		{
			self::$instance = new DBs();
			self::$instance->connectToDB($GLOBALS['db']['dsn'], $GLOBALS['db']['options']);
		}
		return self::$instance;
	}

	function connectToDB($dsn, $options=array())
	{
		$this->dbc = DB::connect($dsn, $options);
		if (DB::isError($this->dbc))
		{ 
			//echo Trace::print_r($this->dbc);
			die($dbc->getMessage());
		}
		return $this->dbc;
	}

	function setUtf8()
	{
		DBs::executeSQL("SET WAIT_TIMEOUT = 300;");
		DBs::executeSQL("SET NAMES 'utf8';");
	}

 	function selectRows($p, /*$from, $what='*', $where='', $group='', $order='', $having='', $limit = '',*/ $fetchMode=DB_FETCHMODE_ASSOC, $assocById=false) {
	 	//i Gets items from one group.
 		$sql = "SELECT {$p['what']}";
		if (isset($p['from'])) { $sql .= " FROM {$p['from']}";	}
		if (isset($p['where'])) { $sql .= " WHERE {$p['where']}";	}
		if (isset($p['group'])) {$sql .= " GROUP BY {$p['group']}";	}
		if (isset($p['order'])) {$sql .= " ORDER BY {$p['order']}";	}
		if (isset($p['having'])) {$sql .= " HAVING {$p['having']}";	}
		if (isset($p['limit'])) {$sql .= " LIMIT {$p['limit']}";	}
		$sql .= ';';
		if (DBS_SHOW_SELECTS)
		{
			echo '<div style="background-color: lightgreen; font-size: 12px;">';
			echo $sql;
			echo '</div>';
		}
		if (DBS_SHOW_EXPLAIN or DBS_GLOBAL_TIMING) $ts = microtime();
		if ($assocById)
		{
			$data = $this->dbc->getAssoc($sql, false, array(), $fetchMode);
		}
		else
		{
			$data = $this->dbc->getAll($sql, array(), $fetchMode);
		}
		if (DBS_SHOW_EXPLAIN or DBS_GLOBAL_TIMING) $ts = microtime() - $ts;
  	DBs::handleIfError($data);
		if (DBS_SHOW_EXPLAIN )
		{
			echo '<div style="background-color: lightblue; font-size: 12px;">';
			print_r($this->dbc->getAll('EXPLAIN '.$sql, array(), DB_FETCHMODE_ASSOC));
			echo "<i>time: $ts s</i>";
			echo '</div>';
		}
		if (DBS_GLOBAL_TIMING) $GLOBALS['timing']['sql-selects'] += $ts;
  	return $data;
 	}

 	function selectRow($p, /*$from, $what='*', $where='', $group='', $order='', $having='', */$fetchMode=DB_FETCHMODE_ASSOC) 
	{
		//print_r($p['where']);
		$p['limit'] = 1;
		$data = DBs::selectRows($p, $fetchMode, false);
		//print_r($data);
		if (count($data) > 0) return $data[0];
		else return Null;
 	}

 	function selectField($p) 
	{
		$p['limit'] = 1;
		$data = DBs::selectRows($p, DB_FETCHMODE_ORDERED);
		//print_r($data);
		if (isset($data[0][0])) return $data[0][0];
		else return Null;
 	}
	
	function insertRow($p) 
	{
		//i Adds one item.
		$strValues = DBs::array2values($p['values']);
		$sql = "INSERT INTO {$p['into']}
		values ( $strValues );";
		$result = $this->dbc->query($sql);
		DBs::handleIfError($result);
		return true;
	}
	
	function updateRows($what, $pairs, $where) {
		//i 
		$strValues = DBs::dict2pairs($pairs);
		$sql = "UPDATE $what SET
  	$strValues WHERE $where;";
  	$result = $this->dbc->query($sql);
		DBs::handleIfError($result);
  	return $this->dbc->affectedRows();
	}
		
	function deleteRows($from, $where) {
		//i Delets one item.
		$sql = "DELETE FROM $from
		WHERE $where;";
		$result = $this->dbc->query($sql);
		DBs::handleIfError($result);
		return $this->dbc->affectedRows();
	}
	
	function executeSQL($sql) {
		//i Adds one item.
  		$result = $this->dbc->query($sql);
  		DBs::handleIfError($result);
  		return true;
	}

 	function querySQL($sql) {
  		$data = $this->dbc->getAll($sql, array(), DB_FETCHMODE_ASSOC);
  		DBs::handleIfError($data);
  		return $data;
 	}

	function selectLastInsertId() {
  		return $this->selectField(array('what' => "LAST_INSERT_ID()"));
 	}
	
	function countRows($table, $where=''){
		//i count how many rows table has
		return DBs::selectField(array('form'=>$table, 'what'=> 'count(*)', 'where'=>$where));
	}
	
	function getMaxRow($from, $rowName){
		$data = DBs::selectRow($from, "MAX($rowName)");
		if (isset($data[0])) return $data[0];
		else return Null;
	}
	
	function array2values($array){
		$result = array();
		foreach($array as $value){
			if (is_string($value)) { 
				if (substr($value, 0, 9) == '#noQuote#')
				{
					$result[] = substr($value, 9); 
				}
				else
				{
					$result[] = "'$value'"; 
				}
			}
			elseif(is_numeric($value)) { $result[] = "$value"; }
			elseif(is_null($value)) { $result[] = 'Null'; }
			elseif(is_bool($value)) { $result[] = intval($value); }
			else{ trigger_error("Error: Unknown value '$value' for trasformation");}
		}
		return implode(', ', $result);
	}

	function dict2pairs($array){
		$result = array();
		foreach($array as $key => $value){
			if (is_string($value)) { 
				if (substr($value, 0, 9) == '#noQuote#')
				{
					$result[] = "$key = ".substr($value, 9); 
				}
				else
				{
					$result[] = "$key = '$value'"; 
				}
			
			
			
			}
			elseif(is_numeric($value)) { $result[] = "$key = $value"; }
			elseif(is_null($value)) { $result[] = "$key = Null"; }
			elseif(is_bool($value)) { $result[] = "$key = " . intval($value); }
			else{ trigger_error("Error: Unknown value '$value' for trasformation");}
		}
		//print_r($result);
		return implode(', ', $result);
	}

	function handleIfError($data)
	{
		if (DB::isError($data))
		{ 
			//$log = $GLOBALS['log']['object'];
			//if ($log->getShowMessage() == 0) //minimal message
			//{
			//	die($data->getMessage());
			//}
			//else
			//{
				$data->backtrace = '';
				echo Trace::print_r($data, $data->getMessage(), '#eeffee');
			/*}
			if ($log->getStoreMessage() == -1)
			{}
			else if ($log->getStoreMessage() == 0)
			{
				$log->store('error', 'db', $data->getMessage());
			}
			else
			{
				$log->store('error', 'db', print_r($data ,true));
			}*/
			die();
		}
	}
}

?>